package io.jenkins.plugins.feishu;

import hudson.Extension;
import hudson.Launcher;
import hudson.model.*;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.Notifier;
import hudson.tasks.Publisher;
import io.jenkins.plugins.feishu.service.FeishuService;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.logging.Logger;
import jenkins.model.Jenkins;
import jenkins.tasks.SimpleBuildStep;
import net.sf.json.JSONObject;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.StaplerRequest2;

public class FeishuNotifier extends Notifier implements SimpleBuildStep {

    private static final Logger LOG = Logger.getLogger(FeishuNotifier.class.getName());

    private final String webHookUrl;
    private final String message;

    @DataBoundConstructor
    public FeishuNotifier(String webHookUrl, String message) {
        super();
        this.webHookUrl = webHookUrl;
        this.message = message;
    }

    public String getWebHookUrl() {
        return webHookUrl;
    }

    public String getMessage() {
        return message;
    }

    @Override
    public DescriptorImpl getDescriptor() {
        return (DescriptorImpl) super.getDescriptor();
    }

    @SuppressWarnings("unchecked")
    public static FeishuNotifier getNotifier(AbstractProject project) {
        Map<Descriptor<Publisher>, Publisher> map = project.getPublishersList().toMap();
        for (Publisher publisher : map.values()) {
            if (publisher instanceof FeishuNotifier) {
                return (FeishuNotifier) publisher;
            }
        }
        return null;
    }

    @Override
    public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener)
            throws InterruptedException, IOException {
        //        return super.perform(build, launcher, listener);
        return true;
    }

    private boolean isEmpty(String s) {
        return s == null || s.trim().isEmpty();
    }

    private Result findPreviousBuildResult(AbstractBuild b) {
        do {
            b = b.getPreviousBuild();
            if (b == null || b.isBuilding()) {
                return null;
            }
        } while ((b.getResult() == Result.ABORTED) || (b.getResult() == Result.NOT_BUILT));
        return b.getResult();
    }

    private boolean isPreviousBuildSuccess(AbstractBuild build) {
        if (build.getResult() == Result.SUCCESS && findPreviousBuildResult(build) == Result.SUCCESS) {
            return true;
        }
        return false;
    }

    public void onStarted(AbstractBuild build, TaskListener listener) {
        if (getDescriptor().isDefaultSendNotificationOnStart()) {
            LOG.info("Prepare Feishu notification for build started...");
            send(build, listener, BuildPhase.STARTED);
        }
    }

    public void onCompleted(AbstractBuild build, TaskListener listener) {
        boolean notifyOnConsecutiveSuccesses = getDescriptor().isDefaultNotifyOnConsecutiveSuccesses();
        boolean previousBuildSuccessful = isPreviousBuildSuccess(build);
        if (notifyOnConsecutiveSuccesses || (!notifyOnConsecutiveSuccesses && !previousBuildSuccessful)) {
            LOG.info("Prepare Feishu notification for build completed...");
            send(build, listener, BuildPhase.COMPLETED);
        }
    }

    private void send(AbstractBuild build, TaskListener listener, BuildPhase phase) {
        String wb = isEmpty(webHookUrl) ? getDescriptor().getWebHookUrl() : webHookUrl;
        String content = isEmpty(message) ? getDescriptor().getMessage() : message;

        String jenkinsUrl = Jenkins.get().getRootUrl() + build.getConsoleUrl();


        long startTimeInMillis = build.getStartTimeInMillis();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String startTime = sdf.format(new Date(startTimeInMillis));

        String jobName = build.getProject().getName();

        String title = "";
        String color = "";

        if (phase == BuildPhase.STARTED) {
            title = "触发构建";
            color = "yellow";
            if (isEmpty(content)) {
                content = "流水线名称: " + jobName + "\\n触发时间: " + startTime;
            }
        }
        if (phase == BuildPhase.COMPLETED) {
            long duration = build.getDuration();
            if (isEmpty(content)) {
                content = "流水线名称: " + jobName + "\\n发布时间: " + startTime + "\\n耗时: " + duration + "ms";
            }
            Result result = build.getResult();
            if (result == Result.SUCCESS) {
                title = "发布成功";
                color = "green";
            } else if (result == Result.ABORTED) {
                title = "发布取消";
                color = "grey";
            } else if (result == Result.FAILURE || result == Result.UNSTABLE) {
                title = "发布失败";
                color = "red";
            }
        }

        try {
            FeishuService client = new FeishuService(wb);
            client.send(color, title, content, jenkinsUrl);
        } catch (Exception e) {
            listener.getLogger().println("发送飞书通知失败");
        }
    }

    @Extension
    public static final class DescriptorImpl extends BuildStepDescriptor<Publisher> {

        private String webHookUrl;

        private String message;
        private boolean defaultSendNotificationOnStart;
        private boolean defaultNotifyOnConsecutiveSuccesses = true;

        public DescriptorImpl() {
            super(FeishuNotifier.class);
            load();
        }

        @Override
        public String getDisplayName() {
            return "Feishu Notifier";
        }

        @Override
        public boolean isApplicable(Class<? extends AbstractProject> aClass) {
            return true;
        }

        @Override
        public boolean configure(StaplerRequest2 req, JSONObject formData) throws FormException {
            req.bindJSON(this, formData);
            save();
            return true;
        }

        public String getWebHookUrl() {
            return webHookUrl;
        }

        public void setWebHookUrl(String webHookUrl) {
            this.webHookUrl = webHookUrl;
        }

        public String getMessage() {
            return message;
        }

        public void setMessage(String message) {
            this.message = message;
        }

        public boolean isDefaultSendNotificationOnStart() {
            return defaultSendNotificationOnStart;
        }

        public boolean isDefaultNotifyOnConsecutiveSuccesses() {
            return defaultNotifyOnConsecutiveSuccesses;
        }

        public void setDefaultSendNotificationOnStart(boolean defaultSendNotificationOnStart) {
            this.defaultSendNotificationOnStart = defaultSendNotificationOnStart;
        }

        public void setDefaultNotifyOnConsecutiveSuccesses(boolean defaultSendNotificationsOnConsecutiveSuccesses) {
            this.defaultNotifyOnConsecutiveSuccesses = defaultSendNotificationsOnConsecutiveSuccesses;
        }
    }
}
